package me.rkfg.ns2gather.client; import static ru.ppsrk.gwt.client.ClientUtils.*; import java.util.Arrays; import java.util.Date; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import me.rkfg.ns2gather.dto.ChatMessageType; import me.rkfg.ns2gather.dto.CheckedDTO; import me.rkfg.ns2gather.dto.GatherState; import me.rkfg.ns2gather.dto.InitStateDTO; import me.rkfg.ns2gather.dto.MapDTO; import me.rkfg.ns2gather.dto.MementoCheckedDTO; import me.rkfg.ns2gather.dto.MessageDTO; import me.rkfg.ns2gather.dto.PlayerDTO; import me.rkfg.ns2gather.dto.ServerDTO; import ru.ppsrk.gwt.client.AlertRuntimeException; import ru.ppsrk.gwt.client.ClientUtils.MyAsyncCallback; import ru.ppsrk.gwt.client.LongPollingClient; import com.google.gwt.cell.client.AbstractCell; import com.google.gwt.cell.client.ButtonCell; import com.google.gwt.cell.client.CheckboxCell; import com.google.gwt.cell.client.FieldUpdater; import com.google.gwt.core.client.EntryPoint; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.dom.client.KeyDownEvent; import com.google.gwt.event.dom.client.KeyDownHandler; import com.google.gwt.i18n.client.DateTimeFormat; import com.google.gwt.safehtml.shared.SafeHtmlBuilder; import com.google.gwt.user.cellview.client.Column; import com.google.gwt.user.cellview.client.DataGrid; import com.google.gwt.user.cellview.client.RowStyles; import com.google.gwt.user.cellview.client.TextColumn; import com.google.gwt.user.client.Cookies; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.Window.Location; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.DockLayoutPanel; import com.google.gwt.user.client.ui.FlexTable; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HasHorizontalAlignment; import com.google.gwt.user.client.ui.HasVerticalAlignment; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.RootLayoutPanel; import com.google.gwt.user.client.ui.ScrollPanel; import com.google.gwt.user.client.ui.SplitLayoutPanel; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.view.client.ListDataProvider; /** * Entry point classes define <code>onModuleLoad()</code>. */ public class NS2G implements EntryPoint { private boolean ready = false; private SoundManager soundManager = new SoundManager(); private CookieSettingsManager cookieSettingsManager = new CookieSettingsManager(); DateTimeFormat format = DateTimeFormat.getFormat("[HH:mm:ss]"); private final NS2GServiceAsync ns2gService = GWT.create(NS2GService.class); private final HTML label_nick = new HTML("Ник"); private final SplitLayoutPanel splitLayoutPanel_main = new SplitLayoutPanel(); private final DockLayoutPanel dockLayoutPanel_chat = new DockLayoutPanel(Unit.EM); private final ScrollPanel scrollPanel_userChat = new ScrollPanel(); private final FlowPanel user_chat = new FlowPanel(); private final TextBox textBox_chatText = new TextBox(); private final Button button_sendChat = new Button("Отправить"); private final SplitLayoutPanel splitLayoutPanel_data = new SplitLayoutPanel(); private final ListDataProvider<PlayerDTO> dataProvider_players = new ListDataProvider<PlayerDTO>(); private final DataGrid<PlayerDTO> dataGrid_players = new DataGrid<PlayerDTO>(); private final Column<PlayerDTO, PlayerDTO> textColumn_playerName = new Column<PlayerDTO, PlayerDTO>(new AbstractCell<PlayerDTO>() { @Override public void render(Context context, PlayerDTO value, SafeHtmlBuilder sb) { value.buildLink(sb, true); } }) { @Override public PlayerDTO getValue(PlayerDTO object) { return object; } }; private final Column<PlayerDTO, Boolean> column_voteComm = new Column<PlayerDTO, Boolean>(new CheckboxCell(true, false)) { @Override public Boolean getValue(PlayerDTO object) { return object.getChecked(); } }; private final ListDataProvider<MapDTO> dataProvider_maps = new ListDataProvider<MapDTO>(); private final DataGrid<MapDTO> dataGrid_maps = new DataGrid<MapDTO>(); private final TextColumn<MapDTO> textColumn_mapName = new TextColumn<MapDTO>() { @Override public String getValue(MapDTO object) { return object.getName(); } }; private final Column<MapDTO, Boolean> column_voteMap = new Column<MapDTO, Boolean>(new CheckboxCell(true, false)) { @Override public Boolean getValue(MapDTO object) { return object.getChecked(); } }; private final ListDataProvider<ServerDTO> dataProvider_servers = new ListDataProvider<ServerDTO>(); private final DataGrid<ServerDTO> dataGrid_servers = new DataGrid<ServerDTO>(); private final TextColumn<ServerDTO> textColumn_serverName = new TextColumn<ServerDTO>() { @Override public String getValue(ServerDTO object) { return object.getName() + " [" + object.getPlayers().size() + "]"; } }; private final Column<ServerDTO, Boolean> column_voteServer = new Column<ServerDTO, Boolean>(new CheckboxCell(true, false)) { @Override public Boolean getValue(ServerDTO object) { return object.getChecked(); } }; private final HorizontalPanel horizontalPanel = new HorizontalPanel(); private final VoteButton button_vote = new VoteButton() { @Override protected void vote() { ns2gService.vote(collectVotes(), new MyAsyncCallback<Void>() { @Override public void onSuccess(Void result) { switchState(); } }); } @Override protected void unvote() { ns2gService.unvote(new MyAsyncCallback<Void>() { @Override public void onSuccess(Void result) { switchState(); } }); } }; private final FlexTable flexTable = new FlexTable(); private final Label label_voted = new Label("0/0"); private final VolumeButton volumeControl = new VolumeButton(cookieSettingsManager) { @Override public void volumeChanged(int newVolume) { setChatVolume(newVolume); if (ready) { soundManager.playSound(NS2Sound.CHAT); } } }; private final HorizontalPanel horizontalPanel_header = new HorizontalPanel(); private final GatherStatusLabel gatherStatusLabel = new GatherStatusLabel(new ClickHandler() { @Override public void onClick(ClickEvent event) { if (!Arrays.asList(GatherState.COMPLETED, GatherState.SIDEPICK, GatherState.PLAYERS).contains( gatherStatusLabel.getGatherState())) { return; } loadVoteResult(); } }); private final Button button_enterNewGather = new Button("Зайти в новый сбор"); private final Button button_logout = new Button("Выход"); private Set<Long> votedPlayers = new HashSet<Long>(); private VoteResultPanel voteResultPanel = new VoteResultPanel(); private ServerPlayersPanel serverPlayersPanel = new ServerPlayersPanel(); private final HorizontalPanel horizontalPanel_voteButton = new HorizontalPanel(); private final HTML html_version = new HTML(); private final Button button_rules = new Button("Правила"); private final FlexTable flexTable_cornerControls = new FlexTable(); private final Column<ServerDTO, String> column_playersList = new Column<ServerDTO, String>(new ButtonCell()) { @Override public String getValue(ServerDTO object) { return "?"; } }; private PlayerDTO myPlayer; private final SplitLayoutPanel splitLayoutPanel_chat = new SplitLayoutPanel(); private final ScrollPanel scrollPanel_systemChat = new ScrollPanel(); private final FlowPanel system_chat = new FlowPanel(); private final Button button_setNick = new Button("Задать ник"); private Timer pingTimer; /** * This is the entry point method. */ public void onModuleLoad() { setupExceptionHandler(); RootLayoutPanel rootLayoutPanel = RootLayoutPanel.get(); rootLayoutPanel.add(splitLayoutPanel_main); horizontalPanel_header.setSpacing(5); splitLayoutPanel_main.addNorth(horizontalPanel_header, 70.0); horizontalPanel_header.setSize("100%", "100%"); horizontalPanel_header.add(gatherStatusLabel); horizontalPanel_header.setCellVerticalAlignment(gatherStatusLabel, HasVerticalAlignment.ALIGN_MIDDLE); horizontalPanel_header.setCellHorizontalAlignment(gatherStatusLabel, HasHorizontalAlignment.ALIGN_CENTER); flexTable_cornerControls.setCellPadding(3); horizontalPanel_header.add(flexTable_cornerControls); horizontalPanel_header.setCellWidth(flexTable_cornerControls, "1px"); horizontalPanel_header.setCellHorizontalAlignment(flexTable_cornerControls, HasHorizontalAlignment.ALIGN_RIGHT); flexTable_cornerControls.setWidget(0, 0, button_rules); button_rules.addClickHandler(new Button_rulesClickHandler()); horizontalPanel_header.setCellWidth(button_rules, "1px"); horizontalPanel_header.setCellHorizontalAlignment(button_rules, HasHorizontalAlignment.ALIGN_RIGHT); button_setNick.addClickHandler(new Button_setNickClickHandler()); flexTable_cornerControls.setWidget(0, 1, button_setNick); button_setNick.setWidth("150px"); flexTable_cornerControls.setWidget(0, 2, button_logout); button_logout.addClickHandler(new Button_logoutClickHandler()); horizontalPanel_header.setCellWidth(button_logout, "1px"); horizontalPanel_header.setCellHorizontalAlignment(button_logout, HasHorizontalAlignment.ALIGN_RIGHT); flexTable_cornerControls.getCellFormatter().setHorizontalAlignment(1, 0, HasHorizontalAlignment.ALIGN_RIGHT); html_version.setText("Версия"); flexTable_cornerControls.setWidget(1, 0, html_version); html_version.setWordWrap(false); html_version.addStyleName("version"); flexTable_cornerControls.getFlexCellFormatter().setColSpan(1, 0, 3); flexTable_cornerControls.getCellFormatter().setHorizontalAlignment(0, 0, HasHorizontalAlignment.ALIGN_CENTER); flexTable_cornerControls.getCellFormatter().setHorizontalAlignment(0, 2, HasHorizontalAlignment.ALIGN_RIGHT); splitLayoutPanel_main.addSouth(dockLayoutPanel_chat, 300.0); horizontalPanel.setSpacing(5); dockLayoutPanel_chat.addNorth(horizontalPanel, 3.0); horizontalPanel.setSize("100%", "100%"); horizontalPanel.add(volumeControl); horizontalPanel.setCellVerticalAlignment(volumeControl, HasVerticalAlignment.ALIGN_MIDDLE); horizontalPanel.setCellWidth(volumeControl, "1px"); horizontalPanel_voteButton.setSpacing(5); horizontalPanel.add(horizontalPanel_voteButton); horizontalPanel.setCellHorizontalAlignment(horizontalPanel_voteButton, HasHorizontalAlignment.ALIGN_CENTER); horizontalPanel.setCellVerticalAlignment(horizontalPanel_voteButton, HasVerticalAlignment.ALIGN_MIDDLE); horizontalPanel_voteButton.add(button_vote); horizontalPanel_voteButton.setCellVerticalAlignment(button_vote, HasVerticalAlignment.ALIGN_MIDDLE); horizontalPanel.setCellVerticalAlignment(button_vote, HasVerticalAlignment.ALIGN_MIDDLE); horizontalPanel.setCellHorizontalAlignment(button_vote, HasHorizontalAlignment.ALIGN_CENTER); horizontalPanel_voteButton.add(label_voted); horizontalPanel_voteButton.setCellVerticalAlignment(label_voted, HasVerticalAlignment.ALIGN_MIDDLE); button_enterNewGather.setVisible(false); button_enterNewGather.addClickHandler(new Button_enterNewGatherClickHandler()); horizontalPanel.add(button_enterNewGather); horizontalPanel.setCellWidth(button_enterNewGather, "300px"); horizontalPanel.setCellVerticalAlignment(button_enterNewGather, HasVerticalAlignment.ALIGN_MIDDLE); horizontalPanel.setCellHorizontalAlignment(button_enterNewGather, HasHorizontalAlignment.ALIGN_RIGHT); flexTable.setCellPadding(5); dockLayoutPanel_chat.addSouth(flexTable, 3.0); flexTable.setSize("100%", "100%"); label_nick.setWordWrap(false); flexTable.setWidget(0, 0, label_nick); textBox_chatText.setMaxLength(ClientSettings.CHAT_MAX_LENGTH); textBox_chatText.addKeyDownHandler(new TextBox_chatTextKeyDownHandler()); flexTable.setWidget(0, 1, textBox_chatText); flexTable.getCellFormatter().setWidth(0, 1, "100%"); textBox_chatText.setWidth("100%"); flexTable.setWidget(0, 2, button_sendChat); button_sendChat.addClickHandler(new Button_sendChatClickHandler()); dockLayoutPanel_chat.add(splitLayoutPanel_chat); scrollPanel_systemChat.setStyleName("border-bs"); splitLayoutPanel_chat.addEast(scrollPanel_systemChat, 400.0); scrollPanel_systemChat.setWidget(system_chat); system_chat.setSize("100%", "100%"); splitLayoutPanel_chat.add(scrollPanel_userChat); scrollPanel_userChat.setStyleName("border-bs"); scrollPanel_userChat.setWidget(user_chat); user_chat.setSize("100%", "100%"); splitLayoutPanel_main.add(splitLayoutPanel_data); splitLayoutPanel_data.addWest(dataGrid_players, 400.0); dataGrid_players.addColumn(column_voteComm); dataGrid_players.setColumnWidth(column_voteComm, "50px"); dataGrid_players.addColumn(textColumn_playerName, "Имя"); splitLayoutPanel_data.addEast(dataGrid_servers, 300.0); dataGrid_servers.addColumn(column_voteServer); dataGrid_servers.setColumnWidth(column_voteServer, "50px"); dataGrid_servers.addColumn(textColumn_serverName, "Сервер"); splitLayoutPanel_data.add(dataGrid_maps); dataGrid_maps.addColumn(column_voteMap); dataGrid_maps.setColumnWidth(column_voteMap, "50px"); dataGrid_maps.addColumn(textColumn_mapName, "Карта"); dataProvider_players.addDataDisplay(dataGrid_players); dataProvider_maps.addDataDisplay(dataGrid_maps); dataProvider_servers.addDataDisplay(dataGrid_servers); dataGrid_servers.addColumn(column_playersList); dataGrid_servers.setColumnWidth(column_playersList, "70px"); init(); ready = true; } private void init() { column_voteComm.setFieldUpdater(new FieldUpdater<PlayerDTO, Boolean>() { @Override public void update(int index, PlayerDTO object, Boolean value) { checkLimit(value, object, dataProvider_players, ClientSettings.voteRules[0].getVotesLimit()); } }); column_voteServer.setFieldUpdater(new FieldUpdater<ServerDTO, Boolean>() { @Override public void update(int index, ServerDTO object, Boolean value) { checkLimit(value, object, dataProvider_servers, ClientSettings.voteRules[2].getVotesLimit()); } }); column_voteMap.setFieldUpdater(new FieldUpdater<MapDTO, Boolean>() { @Override public void update(int index, MapDTO object, Boolean value) { checkLimit(value, object, dataProvider_maps, ClientSettings.voteRules[1].getVotesLimit()); } }); column_playersList.setFieldUpdater(new FieldUpdater<ServerDTO, String>() { @Override public void update(int index, ServerDTO object, String value) { serverPlayersPanel.init(object); serverPlayersPanel.center(); } }); dataGrid_players.setRowStyles(new RowStyles<PlayerDTO>() { @Override public String getStyleNames(PlayerDTO row, int rowIndex) { String result = "big-datagrid"; if (votedPlayers.contains(row.getId())) { result += " voted"; } return result; } }); dataGrid_maps.setRowStyles(new RowStyles<MapDTO>() { @Override public String getStyleNames(MapDTO row, int rowIndex) { return "big-datagrid"; } }); dataGrid_servers.setRowStyles(new RowStyles<ServerDTO>() { @Override public String getStyleNames(ServerDTO row, int rowIndex) { return "big-datagrid"; } }); ns2gService.getPlayer(new AsyncCallback<PlayerDTO>() { @Override public void onSuccess(PlayerDTO result) { initPlayer(result); } @Override public void onFailure(Throwable caught) { if (caught instanceof AnonymousAuthException) { initPlayer(new PlayerDTO(0L, "Anonymous", "", System.currentTimeMillis())); } else { login(); } } }); voteResultPanel.getButton_mute().addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { soundManager.stopSound(NS2Sound.VOTE_END); } }); soundManager.setLoop(NS2Sound.VOTE_END, true); restorePanelsSize(); } private void restorePanelsSize() { splitLayoutPanel_data.setWidgetSize(dataGrid_players, cookieSettingsManager.getDoubleCookie(CookieSettingsManager.PLAYER_PANEL_COOKIE, 400.0)); splitLayoutPanel_data.setWidgetSize(dataGrid_servers, cookieSettingsManager.getDoubleCookie(CookieSettingsManager.SERVER_PANEL_COOKIE, 300.0)); splitLayoutPanel_main.setWidgetSize(dockLayoutPanel_chat, cookieSettingsManager.getDoubleCookie(CookieSettingsManager.CHAT_PANEL_COOKIE, 300.0)); splitLayoutPanel_main.setWidgetSize(horizontalPanel_header, cookieSettingsManager.getDoubleCookie(CookieSettingsManager.HEADER_PANEL_COOKIE, 70.0)); splitLayoutPanel_chat.setWidgetSize(scrollPanel_systemChat, cookieSettingsManager.getDoubleCookie(CookieSettingsManager.CHAT_SYSTEM_PANEL_COOKIE, 400.0)); } protected void postRulesAnnounce() { if (myPlayer.getId().equals(0L)) { addChatMessage( "Вы вошли в Gather анонимно. Вы не можете голосовать и писать в чат, но можете следить за ходом голосования и набором команд. " + "Ознакомьтесь с <a href=\"rules.html\" target=\"_blank\">Правилами</a>", System.currentTimeMillis(), ChatMessageType.SYSTEM); } else { addChatMessage( "Вы заявили свою готовность играть Gather. Ознакомьтесь с <a href=\"rules.html\" target=\"_blank\">Правилами</a>", System.currentTimeMillis(), ChatMessageType.SYSTEM); } } protected void loadInitState() { ns2gService.getInitState(new MyAsyncCallback<InitStateDTO>() { @Override public void onSuccess(InitStateDTO result) { gatherStatusLabel.setGatherState(result.getGatherState()); if (isGatherClosed(result.getGatherState())) { button_vote.setEnabled(false); } updateEnterNewButtonVisibility(); votedPlayers = result.getVotedIds(); dataProvider_players.setList(result.getPlayers()); dataProvider_maps.setList(result.getMaps()); dataProvider_servers.setList(result.getServers()); label_voted.setText(result.getVoteStat()); html_version.setHTML("<a href=\"https://github.com/rkfg/ns2gather/issues\" title=\"Сообщить об ошибке\" target=\"_blank\">" + result.getVersion() + "</a>"); if (result.getPasswords() != null) { addChatMessage(result.getPasswords(), System.currentTimeMillis(), ChatMessageType.SYSTEM); } if (result.getVoteResults() != null) { voteResultPanel.fillFields(result.getVoteResults()); } if (!myPlayer.getId().equals(0L)) { ns2gService.ping(new MyAsyncCallback<Void>() { @Override public void onSuccess(Void result) { runPing(); } }); } runMessageListener(); } @Override public void onFailure(Throwable caught) { super.onFailure(caught); button_enterNewGather.setVisible(true); } }); } protected void fakeLogin() { openPopupPanel(new FakeLoginBox()); } protected void checkLimit(Boolean value, CheckedDTO object, final ListDataProvider<? extends CheckedDTO> dataProvider, int limit) { if (value) { int cnt = 0; for (CheckedDTO checkedDTO : dataProvider.getList()) { if (checkedDTO.getChecked()) { cnt++; } } object.setChecked(cnt < limit); dataProvider.refresh(); } else { object.setChecked(false); } } private void runMessageListener() { LongPollingClient<List<MessageDTO>> client = new LongPollingClient<List<MessageDTO>>(1000) { Long lastMessageUpdate = -ClientSettings.MESSAGES_ROLLBACK; @Override public void success(List<MessageDTO> result) { boolean loadPlayers = false; boolean voteEnded = false; boolean badVote = false; Long id; soundManager.clearQueue(); for (MessageDTO message : result) { if (message.getTimestamp() > lastMessageUpdate) { lastMessageUpdate = message.getTimestamp(); } switch (message.getType()) { case USER_ENTERS: addChatMessage(message.getContent() + " входит.", message.getTimestamp()); loadPlayers = true; soundManager.queue(NS2Sound.USER_ENTERS); break; case USER_LEAVES: id = Long.valueOf(message.getContent()); if (id.equals(myPlayer.getId())) { break; } addPlayerMessage(message, " покидает нас."); votedPlayers.remove(id); dataGrid_players.redraw(); soundManager.queue(NS2Sound.USER_LEAVES); loadPlayers = true; break; case USER_READY: id = Long.valueOf(message.getContent()); votedPlayers.add(id); dataGrid_players.redraw(); addPlayerMessage(message, " готов начать игру!"); break; case USER_UNREADY: id = Long.valueOf(message.getContent()); votedPlayers.remove(id); dataGrid_players.redraw(); addPlayerMessage(message, " отменил готовность начать игру."); break; case CHAT_MESSAGE: addChatMessage(message.getContent(), message.getTimestamp(), ChatMessageType.CHAT); soundManager.queue(NS2Sound.CHAT); break; case VOTE_CHANGE: label_voted.setText(message.getContent()); break; case VOTE_ENDED: voteEnded = true; if (message.getContent().equals("ok")) { addChatMessage("Голосование завершено!", message.getTimestamp()); soundManager.queue(NS2Sound.VOTE_END); button_vote.setEnabled(false); } else { addChatMessage(message.getContent(), message.getTimestamp()); badVote = true; button_vote.setState(true); button_vote.switchState(); soundManager.queue(NS2Sound.REVOTE); } break; case GATHER_STATUS: gatherStatusLabel.setGatherState(GatherState.values()[Integer.valueOf(message.getContent())]); updateEnterNewButtonVisibility(); break; case USER_KICKED: Location.reload(); break; case RUN_TIMER: gatherStatusLabel.runTimer(Long.valueOf(message.getContent())); soundManager.queue(NS2Sound.TIMER); break; case STOP_TIMER: gatherStatusLabel.stopTimer(); break; case MORE_PLAYERS: addChatMessage("Происходит донабор человека для игры в формате 7x7 (8x8)", message.getTimestamp()); soundManager.queue(NS2Sound.MORE); break; case RESET_HIGHLIGHT: resetHighlight(); break; case PICKED: voteResultPanel.loadParticipants(); break; case SERVER_UPDATE: loadServers(); break; case PLAYERS_UPDATE: loadPlayers(); break; default: break; } } if (loadPlayers) { loadPlayers(); } if (voteEnded) { if (!badVote) { loadVoteResult(); } } soundManager.playQueued(); } @Override public void doRPC(LongPollingClient<List<MessageDTO>>.LongPollingAsyncCallback callback) { ns2gService.getNewMessages(lastMessageUpdate, callback); } }; client.start(); } private void addPlayerMessage(MessageDTO message, String messageText) { String name = getNameById(dataProvider_players.getList(), Long.valueOf(message.getContent())); if (name != null) { addChatMessage(name + messageText, message.getTimestamp()); } } protected String getNameById(List<PlayerDTO> list, Long id) { for (PlayerDTO playerDTO : list) { if (playerDTO.getId().equals(id)) { return playerDTO.getEffectiveName(); } } return null; } protected void loadServers() { ns2gService.getServers(new MyAsyncCallback<List<ServerDTO>>() { @Override public void onSuccess(List<ServerDTO> result) { MementoCheckedDTO<ServerDTO> serverMemento = new MementoCheckedDTO<ServerDTO>(); serverMemento.storeChecks(dataProvider_servers.getList()); dataProvider_servers.setList(result); serverMemento.restoreChecks(dataProvider_servers.getList()); } }); } protected void resetHighlight() { votedPlayers = new HashSet<Long>(); dataGrid_players.redraw(); } protected void loadVoteResult() { voteResultPanel.center(gatherStatusLabel.getGatherState()); } protected void addChatMessage(String text, Long timestamp) { addChatMessage(text, timestamp, ChatMessageType.SYSTEM); } protected void loadPlayers() { ns2gService.getConnectedPlayers(new MyAsyncCallback<List<PlayerDTO>>() { @Override public void onSuccess(List<PlayerDTO> result) { MementoCheckedDTO<PlayerDTO> memento = new MementoCheckedDTO<PlayerDTO>(); memento.storeChecks(dataProvider_players.getList()); dataProvider_players.setList(result); memento.restoreChecks(result); } }); } protected void addChatMessage(String text, long timestamp, ChatMessageType messageType) { boolean shouldScroll_user = scrollPanel_userChat.getVerticalScrollPosition() == scrollPanel_userChat .getMaximumVerticalScrollPosition(); boolean shouldScroll_system = scrollPanel_systemChat.getVerticalScrollPosition() == scrollPanel_systemChat .getMaximumVerticalScrollPosition(); HTML msg = buildChatMessage(text, timestamp, messageType); switch (messageType) { case CHAT: user_chat.add(msg); trimChat(user_chat); break; case SYSTEM: system_chat.add(msg); trimChat(system_chat); break; } if (shouldScroll_user) { if (text.contains("<img src=")) { new Timer() { @Override public void run() { scrollPanel_userChat.scrollToBottom(); } }.schedule(ClientSettings.IMAGE_SCROLL_DELAY); } else { scrollPanel_userChat.scrollToBottom(); } } if (shouldScroll_system) { scrollPanel_systemChat.scrollToBottom(); } } private void trimChat(FlowPanel chat) { if (chat.getWidgetCount() > ClientSettings.CHAT_MAX_MESSAGES) { chat.remove(0); } } private HTML buildChatMessage(String text, long timestamp, ChatMessageType messageType) { return new HTML(format.format(new Date(timestamp)) + " <span class=\"" + getCSSClassByMessageType(messageType) + "\">" + text + "</span>"); } private String getCSSClassByMessageType(ChatMessageType messageType) { switch (messageType) { case SYSTEM: return "msg_system"; case CHAT: return "msg_chat"; default: return ""; } } protected void runPing() { pingTimer = new Timer() { @Override public void run() { ns2gService.ping(new MyAsyncCallback<Void>() { @Override public void onSuccess(Void result) { } }); } }; pingTimer.scheduleRepeating(ClientSettings.PING_INTERVAL); } protected void login() { ns2gService.login(new MyAsyncCallback<String>() { @Override public void onSuccess(String result) { if (result != null) { openPopupPanel(new LoginBox(result)); } } }); } private class Button_sendChatClickHandler implements ClickHandler { public void onClick(ClickEvent event) { if (!textBox_chatText.getValue().isEmpty()) { ns2gService.sendChatMessage(textBox_chatText.getValue(), new MyAsyncCallback<Void>() { @Override public void onSuccess(Void result) { } }); textBox_chatText.setText(""); } } } public Long[][] collectVotes() { Long[][] result = new Long[3][]; int i = 0; for (List<? extends CheckedDTO> checkedDTOs : Arrays.asList(dataProvider_players.getList(), dataProvider_maps.getList(), dataProvider_servers.getList())) { LinkedList<Long> voteRow = new LinkedList<Long>(); for (CheckedDTO checkedDTO : checkedDTOs) { if (checkedDTO.getChecked()) { voteRow.add(checkedDTO.getId()); } } if (voteRow.size() > ClientSettings.voteRules[i].getVotesLimit()) { throw new AlertRuntimeException("Слишком много голосов за " + ClientSettings.voteRules[i].getName() + ", ожидается " + ClientSettings.voteRules[i].getVotesRequired() + ", получено " + voteRow.size()); } result[i++] = (Long[]) voteRow.toArray(new Long[0]); } return result; } private void setChatVolume(int volume) { for (NS2Sound ns2Sound : Arrays.asList(NS2Sound.CHAT, NS2Sound.USER_ENTERS, NS2Sound.USER_LEAVES)) { soundManager.setVolume(ns2Sound, volume / 200.0); } } private class TextBox_chatTextKeyDownHandler implements KeyDownHandler { public void onKeyDown(KeyDownEvent event) { if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) { button_sendChat.click(); } } } private class Button_logoutClickHandler implements ClickHandler { public void onClick(ClickEvent event) { switch (gatherStatusLabel.getGatherState()) { case CLOSED: case OPEN: case ONTIMER: if (!Window.confirm("Вы действительно хотите покинуть сбор? Если все остальные участники проголосуют, " + "вы не сможете вернуться к ним и попадёте в новый сбор.")) { return; } break; case PLAYERS: case SIDEPICK: Window.alert("Голосование уже завершено. Пожалуйста, дождитесь выбора сторон и набора команд. " + "Не закрывайте вкладку, если вы покинете сбор на этой стадии, к вам могут быть применены санкции согласно правилам."); return; case COMPLETED: if (!Window .confirm("Вы действительно хотите покинуть сбор? После входа вы попадёте в новый сбор и больше не сможете посмотреть " + "результаты этого сбора и пароль для подключения. Вы также можете нажать кнопку «Зайти в новый сбор», чтобы попасть в новый сбор без перезахода.")) { return; } break; } if (pingTimer != null) { pingTimer.cancel(); } ns2gService.logout(new MyAsyncCallback<Void>() { @Override public void onSuccess(Void result) { Cookies.removeCookie(CookieSettingsManager.REMEMBER_STEAM_ID); Location.reload(); } }); } } private class Button_enterNewGatherClickHandler implements ClickHandler { public void onClick(ClickEvent event) { ns2gService.resetGatherPresence(new MyAsyncCallback<Void>() { @Override public void onSuccess(Void result) { Location.reload(); } }); } } public void updateEnterNewButtonVisibility() { button_enterNewGather.setVisible(gatherStatusLabel.getState() == GatherState.COMPLETED); } private class Button_rulesClickHandler implements ClickHandler { public void onClick(ClickEvent event) { openWindowRootRelative("rules.html"); } } public void runSizeSaver() { new Timer() { @Override public void run() { cookieSettingsManager.setDoubleCookie(CookieSettingsManager.PLAYER_PANEL_COOKIE, splitLayoutPanel_data.getWidgetSize(dataGrid_players)); cookieSettingsManager.setDoubleCookie(CookieSettingsManager.SERVER_PANEL_COOKIE, splitLayoutPanel_data.getWidgetSize(dataGrid_servers)); cookieSettingsManager.setDoubleCookie(CookieSettingsManager.CHAT_PANEL_COOKIE, splitLayoutPanel_main.getWidgetSize(dockLayoutPanel_chat)); cookieSettingsManager.setDoubleCookie(CookieSettingsManager.HEADER_PANEL_COOKIE, splitLayoutPanel_main.getWidgetSize(horizontalPanel_header)); cookieSettingsManager.setDoubleCookie(CookieSettingsManager.CHAT_SYSTEM_PANEL_COOKIE, splitLayoutPanel_chat.getWidgetSize(scrollPanel_systemChat)); } }.scheduleRepeating(ClientSettings.SIZE_SAVE_INTERVAL); } private void initPlayer(PlayerDTO result) { myPlayer = result; updateNickURL(); voteResultPanel.setId(myPlayer.getId()); // send initial ping to show our presence loadInitState(); postRulesAnnounce(); runSizeSaver(); } private void updateNickURL() { SafeHtmlBuilder sb = new SafeHtmlBuilder(); myPlayer.buildLink(sb, false); label_nick.setHTML(sb.toSafeHtml().asString()); } public static boolean isGatherClosed(GatherState gatherState) { return Arrays.asList(GatherState.COMPLETED, GatherState.SIDEPICK, GatherState.PLAYERS).contains(gatherState); } private class Button_setNickClickHandler implements ClickHandler { public void onClick(ClickEvent event) { final String newNick = Window.prompt("Укажите ник.", myPlayer.getNick() != null ? myPlayer.getNick() : myPlayer.getName()); if (newNick != null) { ns2gService.changeNick(newNick, new MyAsyncCallback<Void>() { @Override public void onSuccess(Void result) { myPlayer.setNick(newNick); updateNickURL(); } }); } } } }